#pragma once

#include <common.hpp>
#ifdef ZZZ_OS_WIN
#include <conio.h>
#endif

namespace zzz{
// Bit Check
inline bool CheckBit(const int check, const int bit){return ((check & bit)!=0)?true:false;}
inline void SetBit(int &flag, const int bit){flag |= bit;}
inline void ClearBit(int &flag, const int bit){flag &= ~bit;}
inline void ToggleBit(int &flag, const int bit){flag ^= bit;}

inline bool CheckBit(const zuint check, const int bit){return ((check & bit)!=0)?true:false;}
inline void SetBit(zuint &flag, const int bit){flag |= bit;}
inline void ClearBit(zuint &flag, const int bit){flag &= ~bit;}
inline void ToggleBit(zuint &flag, const int bit){flag ^= bit;}

#ifdef ZOPTIMIZE_SETCLEARBIT
inline void SetClearBit(int &flag, const int bit, bool f)
{
  flag ^= (-int(f) ^ flag) &bit;
}

inline void SetClearBit(zuint &flag, const zuint bit, bool f)
{
  flag ^= (-int(f) ^ flag) &bit;
}

#else
inline void SetClearBit(int &flag, const int bit, bool f){if (f) SetBit(flag,bit); else ClearBit(flag,bit);}
inline void SetClearBit(zuint &flag, const zuint bit, bool f){if (f) SetBit(flag,bit); else ClearBit(flag,bit);}

#endif

// Misc
template <typename InputIterator1, typename InputIterator2>
bool SafeEqual(const InputIterator1 &first1, const InputIterator1 &last1,
  const InputIterator2 &first2, const InputIterator2 &last2)
{
  InputIterator1 cur1 = first1;
  InputIterator2 cur2 = first2;
  while ((cur1 != last1)) {
    if (cur2 == last2)
      return false;
    if (*cur1 != *cur2)   // or: if (!pred(*first1, *first2)), for pred version
      return false;
    cur1++; cur2++;
  }
  return true;
}

template <typename InputIterator1, typename InputIterator2, typename Pred>
bool SafeEqual(const InputIterator1 &first1, const InputIterator1 &last1,
               const InputIterator2 &first2, const InputIterator2 &last2, const Pred &pred)
{
  InputIterator1 cur1 = first1;
  InputIterator2 cur2 = first2;
  while ((cur1 != last1)) {
    if (cur2 == last2)
        return false;
      if (!pred(*cur1, *cur2))
        return false;
    cur1++; cur2++;
  }
  return true;
}

inline void PressAnyKeyToContinue()
{
  cout<<"~~~ HIT A KEY TO CONTINUE ~~~"<<endl;
  _getch();
}

inline string GetEnv(const string &name)
{
  char *value = getenv(name.c_str());
  if (value != NULL)
    return string(value);
  else
    return string("");
}
}   // namespace zzz
